上一篇說明了三種建立 Spy 物件的方法,透過 Spy 物件的替換可以讓單元測試不用與外部資源相依,進而減少測試程式的準備成本;這一篇會來介紹在 Spy 物件中有哪些比較常用的方法可以使用。
除了前一篇所利用的 returnValue
方法決定 Spy 服務方法回傳值之外,Jasmine 也針對不同的情境提供了不同的方法。
callThrough()
- 當我們希望服務方法能依正式作業的方法執行,但又想要驗證呼叫此方法的參數是否正確時,就可以使用 callThrough()
方法。
spyOn(shoppingCartService, 'add').and.callThrough()
callFake(fn)
- 當服務方法會依不同的測試情境所傳入的值,而有不一樣的回傳值時候,可以利用 callFake()
方法,利用一方法來判斷與決定回傳值。
spyOn(shoppingCartService, 'add').and.callFake((product) => {
...
});
throwError(something)
- 此方法則可以讓我們指定服務方法拋出例外錯誤。
spyOn(shoppingCartService, 'add').and.throwError('error message')
在驗證的部份,Jasmine 也提供了用來驗證目標程式與 Spy 物件互動的方法。
toHaveBeenCalled()
- 這個方法用來驗證 Spy 物件的方法是否有被呼叫。
expect(shoppingCartService.add).toHaveBeenCalled();
toHaveBeenCalledOnceWith(expected)
- 用來驗證 Spy 物件方法是否依指定參數被呼叫一次。
expect(shoppingCartService.add).toHaveBeenCalledOneWith(new Product({}));
toHaveBeenCalledWith(expected)
- 用來驗證 Spy 物件方法是否依指定參數被呼叫。
expect(shoppingCartService.add).toHaveBeenCalledWith(new Product({}));
toHaveBeenCalledTimes(times)
- 用來驗證 Spy 物件方法是否有被呼叫的次數
expect(shoppingCartService.add).toHaveBeenCalledTimes(1);
接下來來拿先前「加入購作車」動作的測試程式,原本是驗證 ShoppingCartService
服務內記錄的資料是否符合預期;但如果服務的方法是需要透 HttpClient 存取資料庫的時候,就無法使用這樣的驗證方式,而改用驗證元件與服務之間的互動。
it('當將產品 C 新增至購物車時, 購物車服務應記錄 1 筆資料', () => {
// Arrange
const shoppingCartService = TestBed.inject(ShoppingCartService);
spyOn(shoppingCartService, 'add').and.callThrough();
const product = new Product({ id: 3, name: '產品 C', price: 10 });
component.product = product;
fixture.detectChanges();
// Act
const button = fixture.debugElement.queryAll(By.css('button'))[1];
button.nativeElement.click();
// Assert
expect(shoppingCartService.add).toHaveBeenCalledWith(product);
});
如上面程式,與先前測試程式有兩個地方不同,首先利用 spyOn
方法針對 ShoppingCartService
的 add()
方法建立 Spy 物件,並讓此方法維持著原本的作業。其次利用 toHaveBeenCallWith()
方法驗證在按下「加入購物車」按鈕時,是否有呼叫到 ShoppingCartService
的 add()
方法,且傳入的參數為 product
變數。
最後就執行 ng test
來確認測試的結果。
這一篇說明了 Spy 物件的設定與驗證方法,完整的測試程式可以參考 GitHub。接下來,則繼續說明在表單上的驗證方式要如何撰寫。